from flask import request

from app.persistence.HouseInfo import HouseInfo
from app.persistence.Address import Address
from app.persistence.Facilities import Facility
from app.service.houseService import HouseService
from app.util.response import make_response, ErrorCode
from app.util.validation import validate_input
from app.util.jwtUtil import get_user_id_from_token
from app.extensions import db


class HouseController:

    @staticmethod
    def create_house():
        """创建房源（需要登录）"""
        # 身份验证
        auth_header = request.headers.get('Authorization')
        user_id = get_user_id_from_token(auth_header)
        if not user_id:
            return make_response(error_code=ErrorCode.USER_TOKEN_INVALID)

        # 基础数据验证
        data = request.get_json()
        required_fields = {
            'house': ['title', 'property_type', 'rental_type', 'area', 'price'],
            'address': ['province', 'city', 'district', 'street', 'location'],
            'facility': []  # 设施全部可选
        }

        if not validate_input(data, required_fields):
            return make_response(error_code=ErrorCode.INVALID_INPUT)

        # 额外验证location格式
        location = data['address']['location']
        is_valid_location = False

        # 验证GeoJSON格式
        if isinstance(location, dict):
            if 'type' in location and location['type'] == 'Point' and 'coordinates' in location:
                coords = location['coordinates']
                if len(coords) == 2 and all(isinstance(x, (int, float)) for x in coords):
                    is_valid_location = (-180 <= coords[0] <= 180) and (-90 <= coords[1] <= 90)

            # 验证简化格式
            elif 'lng' in location and 'lat' in location:
                lng, lat = location['lng'], location['lat']
                if all(isinstance(x, (int, float)) for x in [lng, lat]):
                    is_valid_location = (-180 <= lng <= 180) and (-90 <= lat <= 90)

        if not is_valid_location:
            return make_response(
                error_code=ErrorCode.INVALID_INPUT,
                extra_msg="位置格式应为{'type':'Point','coordinates':[经度,纬度]}或{'lng':经度,'lat':纬度}"
            )

        try:
            # 添加用户ID并创建
            data['house']['userid'] = user_id
            house = HouseService.create_house(
                data['house'],
                data['address'],
                data.get('facility', {})
            )
            return make_response(
                data={'houseid': house.houseid},
                extra_msg="房源创建成功"
            )
        except ValueError as e:
            return make_response(
                error_code=ErrorCode.INVALID_INPUT,
                extra_msg=str(e))
        except Exception as e:
            return make_response(
                error_code=ErrorCode.SERVER_ERROR,
                extra_msg=str(e))

    @staticmethod
    def delete_house(houseid):
        """删除房源（需要验证所有权）"""
        # 身份验证
        auth_header = request.headers.get('Authorization')
        user_id = get_user_id_from_token(auth_header)
        if not user_id:
            return make_response(error_code=ErrorCode.USER_TOKEN_INVALID)

        try:
            # 所有权验证
            if not HouseService.is_house_owner(houseid, user_id):
                return make_response(error_code=ErrorCode.FORBIDDEN)

            if HouseService.delete_house(houseid):
                return make_response(extra_msg="房源删除成功")
            return make_response(error_code=ErrorCode.HOUSE_NOT_FOUND)
        except Exception as e:
            return make_response(
                error_code=ErrorCode.SERVER_ERROR,
                extra_msg=str(e)
            )

    @staticmethod
    def update_house_unified(houseid):
        """统一更新房源信息（基础信息、地址、设施）"""
        # 身份验证
        auth_header = request.headers.get('Authorization')
        user_id = get_user_id_from_token(auth_header)
        if not user_id:
            return make_response(error_code=ErrorCode.USER_TOKEN_INVALID)

        # 所有权验证
        if not HouseService.is_house_owner(houseid, user_id):
            return make_response(error_code=ErrorCode.FORBIDDEN)

        data = request.get_json()
        if not data:
            return make_response(error_code=ErrorCode.INVALID_INPUT)

        # 使用模型类定义的字段白名单
        field_groups = {
            'house': HouseInfo.updatable_fields(),
            'address': Address.updatable_fields(),
            'facility': Facility.updatable_fields()
        }

        # 分组数据
        updates = {
            'house': {},
            'address': {},
            'facility': {}
        }

        # 验证并分组字段
        invalid_fields = []
        for key, value in data.items():
            found = False
            for group, fields in field_groups.items():
                if key in fields:
                    updates[group][key] = value
                    found = True
                    break

            if not found:
                invalid_fields.append(key)

        if invalid_fields:
            return make_response(
                error_code=ErrorCode.INVALID_INPUT,
                extra_msg=f"以下字段不允许更新: {', '.join(invalid_fields)}"
            )

        try:
            # 特殊处理 location 字段
            if 'location' in updates['address']:
                location = updates['address']['location']
                is_valid = False

                # 验证 GeoJSON 格式
                if isinstance(location, dict):
                    if location.get('type') == 'Point' and 'coordinates' in location:
                        coords = location['coordinates']
                        if len(coords) == 2 and all(isinstance(x, (int, float)) for x in coords):
                            is_valid = True

                    # 验证简化格式
                    elif 'lng' in location and 'lat' in location:
                        lng, lat = location['lng'], location['lat']
                        if all(isinstance(x, (int, float)) for x in [lng, lat]):
                            # 转换为标准 GeoJSON 格式
                            updates['address']['location'] = {
                                'type': 'Point',
                                'coordinates': [lng, lat]
                            }
                            is_valid = True

                if not is_valid:
                    return make_response(
                        error_code=ErrorCode.INVALID_INPUT,
                        extra_msg="位置格式应为GeoJSON格式 {'type':'Point','coordinates':[经度,纬度]} 或简化格式 {'lng':经度,'lat':纬度}"
                    )

            # 执行更新
            results = {}
            db.session.begin_nested()  # 使用嵌套事务以便部分回滚

            try:
                if updates['house']:
                    results['house'] = HouseService.update_house(houseid, updates['house'])

                if updates['address']:
                    # 特殊处理 location 字段转换
                    if 'location' in updates['address']:
                        loc_data = updates['address']['location']
                        if isinstance(loc_data, dict) and 'coordinates' in loc_data:
                            # 转换为 WKT 格式 (POINT(lng lat))
                            wkt = f"POINT({loc_data['coordinates'][0]} {loc_data['coordinates'][1]})"
                            updates['address']['location'] = wkt

                    results['address'] = HouseService.update_address(houseid, updates['address'])

                if updates['facility']:
                    results['facility'] = HouseService.update_facility(houseid, updates['facility'])

                db.session.commit()

                # 构建响应
                updated_parts = [k for k, v in results.items() if v]
                if updated_parts:
                    return make_response(
                        data={'updated': updated_parts},
                        extra_msg=f"成功更新: {', '.join(updated_parts)}"
                    )
                return make_response(extra_msg="未更新任何字段")

            except Exception as e:
                db.session.rollback()  # 回滚嵌套事务
                raise e

        except ValueError as e:
            return make_response(
                error_code=ErrorCode.INVALID_INPUT,
                extra_msg=str(e)
            )
        except Exception as e:
            db.session.rollback()
            return make_response(
                error_code=ErrorCode.SERVER_ERROR,
                extra_msg=str(e))



    @staticmethod
    def get_house(houseid):
        """获取房源完整详情（公开接口）"""
        try:
            # 获取分页参数
            page = int(request.args.get('page', 1))
            per_page = int(request.args.get('per_page', 5))

            house_detail = HouseService.get_house_info(houseid, page, per_page)
            if house_detail:
                return make_response(data=house_detail)
            return make_response(error_code=ErrorCode.HOUSE_NOT_FOUND)
        except ValueError:
            return make_response(error_code=ErrorCode.INVALID_INPUT)
        except Exception as e:
            return make_response(
                error_code=ErrorCode.SERVER_ERROR,
                extra_msg=str(e)
            )

    @staticmethod
    def search_houses():
        """搜索房源（公开接口）"""
        try:
            # 参数处理
            filters = request.args.to_dict()
            page = int(request.args.get('page', 1))
            per_page = int(request.args.get('per_page', 10))

            # 设施参数类型转换
            for key in list(filters.keys()):
                if key.startswith('has_'):
                    val = filters[key].lower()
                    if val in ['true', '1', 'yes']:
                        filters[key] = True
                    elif val in ['false', '0', 'no']:
                        filters[key] = False
                    else:
                        del filters[key]  # 移除无效值

            # 数字类型转换
            for num_field in ['min_price', 'max_price', 'bedroom_count']:
                if num_field in filters:
                    try:
                        filters[num_field] = float(filters[num_field])
                    except ValueError:
                        del filters[num_field]

            result = HouseService.search_houses(filters, page, per_page)
            return make_response(data=result)
        except ValueError:
            return make_response(error_code=ErrorCode.INVALID_INPUT)
        except Exception as e:
            return make_response(
                error_code=ErrorCode.SERVER_ERROR,
                extra_msg=str(e)
            )

    @staticmethod
    def get_user_houses():
        """获取当前用户的房源（按状态分类）"""
        # 身份验证
        auth_header = request.headers.get('Authorization')
        user_id = get_user_id_from_token(auth_header)
        if not user_id:
            return make_response(error_code=ErrorCode.USER_TOKEN_INVALID)

        try:
            houses_by_status = HouseService.get_houses_by_user(user_id)
            return make_response(data=houses_by_status)
        except Exception as e:
            return make_response(
                error_code=ErrorCode.SERVER_ERROR,
                extra_msg=str(e)
            )

    @staticmethod
    def get_all_houses():
        """获取所有房源列表（分页，公开接口）"""
        try:
            page = int(request.args.get('page', 1))
            per_page = int(request.args.get('per_page', 10))

            result = HouseService.get_all_houses(page, per_page)
            return make_response(data=result)
        except ValueError:
            return make_response(error_code=ErrorCode.INVALID_INPUT)
        except Exception as e:
            return make_response(
                error_code=ErrorCode.SERVER_ERROR,
                extra_msg=str(e)
            )